/*
 *  2004/5/11 created
 *
 */
package jaoso.framework.service.impl;

import jaoso.framework.dao.AccountDAO;
import jaoso.framework.dao.RightDAO;
import jaoso.framework.dao.RoleDAO;

import jaoso.framework.domain.Account;
import jaoso.framework.domain.Right;
import jaoso.framework.domain.Role;

import jaoso.framework.exception.AccountAlreadyExistException;
import jaoso.framework.exception.BusinessException;
import jaoso.framework.exception.DAOException;
import jaoso.framework.exception.GroupExistException;
import jaoso.framework.exception.RightExistException;

import jaoso.framework.security.Acl;
import jaoso.framework.security.ProtectedResource;

import jaoso.framework.service.SecurityService;

import jaoso.framework.util.MyBeanUtils;
import jaoso.framework.util.MyUtils;

import org.apache.log4j.Category;
import org.apache.log4j.Logger;

import org.springframework.orm.hibernate.LocalSessionFactoryBean;

import com.yl.cap.analyst.user.domain.User;

import java.io.Serializable;

import java.lang.reflect.InvocationTargetException;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @author edgeloner
 */
public class SecurityServiceImpl extends BaseService implements SecurityService
{
    /** log */
    Category log = Logger.getLogger("popedom");

    /** accountDAO */
    private AccountDAO accountDAO;

    /** box and group mapping collection */
    private Acl acl;

    /** Right dao */
    private RightDAO rightDAO;

    /** Role dao */
    private RoleDAO groupDAO;

    private LocalSessionFactoryBean lsfb;

    public LocalSessionFactoryBean getLsfb()
    {
        return lsfb;
    }

    public void setLsfb(LocalSessionFactoryBean lsfb)
    {
        this.lsfb = lsfb;
    }

    /**
     * DOCUMENT ME!
     * 
     * @param dao
     *            DOCUMENT ME!
     */
    public final void setAccountDAO(final AccountDAO dao)
    {
        accountDAO = dao;
    }

    /**
     * DOCUMENT ME!
     * 
     * @param a
     *            DOCUMENT ME!
     */
    public final void setAcl(final Acl a)
    {
        this.acl = a;
    }

    /**
     * @param dao
     *            group DAO
     */
    public final void setGroupDAO(final RoleDAO dao)
    {
        this.groupDAO = dao;
    }

    /**
     * @param dao
     *            right DAO
     */
    public final void setRightDAO(final RightDAO dao)
    {
        this.rightDAO = dao;
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#changeAccountGroup(java.io.Serializable,
     *      java.io.Serializable)
     */
    public final void changeAccountRole(final Serializable accountId,
            final Serializable groupId) throws BusinessException
    {
        Account account = findAccountById(accountId);
        Role group = findRoleById(groupId);
        Role ogroup = account.getGroup();

        try
        {
            if ((ogroup != null) && !MyUtils.isBlank(ogroup.getId())
                    && !ogroup.getId().equals(group.getId()))
            {
                ogroup.getAccounts().remove(account);
                account.setGroup(group);
                group.getAccounts().add(account);
                groupDAO.updateGroup(ogroup);
            } else if ((ogroup == null) || MyUtils.isBlank(ogroup.getId()))
            {
                account.setGroup(group);
                group.getAccounts().add(account);
            }

            groupDAO.updateGroup(group);
            accountDAO.updateAccount(account);
        } catch (DAOException e)
        {
            throw new BusinessException(e.getMessage());
        }

        initSecurity();
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#createRight(jaoso.framework.dto.RightDTO)
     */
    public final void createRight(final Right right) throws BusinessException,
            RightExistException
    {
        if (rightDAO.isExist(right))
        {
            throw new RightExistException("right already exist");
        }

        try
        {
            rightDAO.createRight(right);
        } catch (DAOException e)
        {
            throw new BusinessException(e.getMessage());
        }

        initSecurity();
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#createGroup(jaoso.framework.dto.GroupDTO)
     */
    public final void createRole(final Role group, final String[] rights)
            throws BusinessException, GroupExistException
    {
        if (group == null)
        {
            throw new BusinessException("group cant not be null!");
        }

        if (groupDAO.isExist(group.getDesc()))
        {
            throw new GroupExistException("group desc already exist!");
        }

        try
        {
            Set rightset = new HashSet();
            Right right;

            for (int i = 0, n = rights.length; i < n; i++)
            {
                right = rightDAO.getRight(rights[i]);

                if (right != null)
                {
                    right.getGroups().add(group);
                    rightset.add(right);
                    rightDAO.updateRight(right);
                }
            }

            group.setRights(rightset);
            groupDAO.createGroup(group);
            initSecurity();
        } catch (DAOException e)
        {
            log.error("create group error: ", e);
            throw new BusinessException(e.getMessage());
        }
    }

    //==========================================================================

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.application.service.SecurityService#findAccountById(java.lang.String)
     */
    public final Account findAccountById(final Serializable id)
    {
        if (MyUtils.isBlank(id))
        {
            return null;
        }

        return accountDAO.getAccount(id);
    }

    //==========================================================================

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.application.service.SecurityService#findAccountByName(java.lang.String)
     */
    public final Account findAccountByName(final String name)
            throws BusinessException
    {
        if (MyUtils.isBlank(name))
        {
            return null;
        }

        Account account = null;

        try
        {
            account = accountDAO.getAccountByName(name);
        } catch (DAOException e)
        {
            log.error("findAccountByName error: " + e);
            throw new BusinessException(e.getMessage());
        }

        return account;
    }

    //==========================================================================

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.application.service.SecurityService#findAllAccount()
     */
    public final Account[] findAllAccount() throws BusinessException
    {
        Account[] entitys = null;

        try
        {
            entitys = accountDAO.findAllAccount();
        } catch (DAOException e)
        {
            log.error("findAllAccount error: " + e);
            throw new BusinessException(e.getMessage());
        }

        if (MyUtils.isBlank(entitys))
        {
            return null;
        }

        return entitys;
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#findAllGroup()
     */
    public final Role[] findAllGroup() throws BusinessException
    {
        Role[] entitys = null;

        try
        {
            entitys = groupDAO.findAllGroup();
        } catch (DAOException e)
        {
            log.error("findAllAccount error: " + e);
            throw new BusinessException(e.getMessage());
        }

        if (MyUtils.isBlank(entitys))
        {
            return null;
        }

        return entitys;
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#findAllRight()
     */
    public final Right[] findAllRight() throws BusinessException
    {
        Right[] entitys = null;

        try
        {
            entitys = rightDAO.findAllRight();
        } catch (DAOException e)
        {
            log.error("findAllAccount error: " + e);
            throw new BusinessException(e.getMessage());
        }

        if (MyUtils.isBlank(entitys))
        {
            return null;
        }

        return entitys;
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#findGroupById(java.io.Serializable)
     */
    public final Role findRoleById(final Serializable id)
            throws BusinessException
    {
        Role group = null;

        try
        {
            group = groupDAO.getGroup(id);
        } catch (DAOException e)
        {
            throw new BusinessException(e.getMessage());
        }

        return group;
    }

    //==========================================================================

    /**
     * DOCUMENT ME!
     * 
     * @throws BusinessException
     *             DOCUMENT ME!
     */
    public final void initSecurity() throws BusinessException
    {
        //load all rights to acl
        acl.setProtectedResourcesMap(loadRights());
        log.info("*****************init security success!***************");
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.application.service.SecurityService#login(java.lang.String,
     *      java.lang.String)
     */
    public final Account login(final String name, final String password)
            throws BusinessException
    {
        Account account = null;

        //use jaas
        //        try {
        //
        //            // let the LoginContext instantiate a new Subject
        //            LoginContext lc = new LoginContext("JaosoLogin",
        //                    new SimpleCallbackHandler(name, MyUtils.toMD5(password)));
        //            lc.login();
        //        } catch (LoginException e) {
        //
        //            throw new BusinessException(e.getMessage());
        //        }
        account = findAccountByName(name);

        if ((account == null)
                || !account.getPassword().equals(MyUtils.toMD5(password)))
        {
            throw new BusinessException("password not match");
        }

        return account;
    }

    //==========================================================================

    /**
     * DOCUMENT ME!
     * 
     * @param account
     *            DOCUMENT ME!
     * 
     * @throws BusinessException
     *             DOCUMENT ME!
     * @throws AccountAlreadyExistException
     *             DOCUMENT ME!
     */
    public final void register(final Account account) throws BusinessException,
            AccountAlreadyExistException
    {
        if (account == null)
        {
            throw new BusinessException("account can not be null");
        }

        if (accountDAO.isExist(account.getName()))
        {
            throw new AccountAlreadyExistException("account already exist!");
        }

        account.setPassword(MyUtils.toMD5(account.getPassword()));

        /*Date date = new Date();
        account.getManager().setCreatedate(date);
        account.getManager().setLastdate(date);
        account.getManager().setCreatedate(date);
        account.getManager().setLastdate(date);*/

        try
        {
            accountDAO.createAccount(account);
        } catch (DAOException e)
        {
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#removeAccount(java.io.Serializable)
     */
    public final void removeAccount(final Serializable id)
            throws BusinessException
    {
        if (id == null)
        {
            throw new BusinessException("accounts can't be null");
        }

        try
        {
            accountDAO.removeAccount(id);
        } catch (DAOException e)
        {
            log.error("update Account error: ", e);
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#removeAccount(java.io.Serializable[])
     */
    public final void removeAccount(final Serializable[] ids)
            throws BusinessException
    {
        if (ids == null)
        {
            throw new BusinessException("accounts can't be null");
        }

        for (int i = 0, n = ids.length; i < n; i++)
        {
            removeAccount(ids[i]);
        }

        //initSecurity();
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#removeRight(java.io.Serializable[])
     */
    public final void removeRight(final Serializable[] ids)
            throws BusinessException
    {
        if (MyUtils.isBlank(ids))
        {
            throw new BusinessException("rights can't be null");
        }

        try
        {
            rightDAO.removeRight(ids);
        } catch (DAOException e)
        {
            log.error("remove right error: ", e);
            throw new BusinessException(e.getMessage());
        }

        initSecurity();
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#removeGroup(java.io.Serializable[])
     */
    public final void removeRole(final Serializable[] ids)
            throws BusinessException,AccountAlreadyExistException
    {
        if (MyUtils.isBlank(ids))
        {
            throw new BusinessException("groups can't be null");
        }

        try
        {
            groupDAO.removeGroup(ids);
        }
        catch(AccountAlreadyExistException e)
        {
            log.error("remove group error: ", e);
            throw new AccountAlreadyExistException(e.getMessage());   
        }
        catch (DAOException e)
        {
            log.error("remove group error: ", e);
            throw new BusinessException(e.getMessage());
        }

        initSecurity();
    }

    //==========================================================================

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.application.service.SecurityService#updateAccount(jaoso.application.dto.AccountDTO)
     */
    public final void updateAccount(final Account account)
            throws BusinessException, AccountAlreadyExistException
    {
        if ((account == null) || MyUtils.isBlank(account.getId()))
        {
            throw new BusinessException("account can't not be null");
        }

        if (accountDAO.isExist(account.getName(), account.getId()))
        {
            throw new AccountAlreadyExistException("account already exist!");
        }

        Account entity = null;

        try
        {
            entity = accountDAO.getAccount(account.getId());

            if (entity == null)
            {
                throw new BusinessException("account not found ");
            }

            User person = entity.getUser();
            //MyBeanUtils.copyProperties(person, account.getUser());
            person.setRealName(account.getUser().getRealName());
            entity.setName(account.getName());
            if (!MyUtils.isBlank(account.getPassword()))
            {
                entity.setPassword(account.getPassword());
            }
            if (account.getGroup()!=null && !entity.getGroup().getId().equals(account.getGroup().getId()))
            {
                entity.setGroup(account.getGroup());    
            }
            if (account.getUser().getGroup()!=null && !account.getUser().getGroup().getId().equals(entity.getUser().getGroup().getId()))
            {
                entity.getUser().setGroup(account.getUser().getGroup());    
            }
                account.setUser(person);
            //MyBeanUtils.copyProperties(entity, account);

            //convert apssword to MD5
            entity.setPassword(MyUtils.toMD5(entity.getPassword()));
            //accountDAO.updateAccount(entity);
        } catch (DAOException e)
        {
            log.error("update Account error: ", e);
            throw new BusinessException(e.getMessage());
        } /*catch (IllegalAccessException e)
        {
            log.error("update Account error: ", e);
            throw new BusinessException(e.getMessage());
        } catch (InvocationTargetException e)
        {
            log.error("update Account error: ", e);
            throw new BusinessException(e.getMessage());
        }*/
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#updateRight(jaoso.framework.dto.RightDTO)
     */
    public final void updateRight(final Right right) throws BusinessException,
            RightExistException
    {
        if (right == null)
        {
            return;
        }

        if (rightDAO.isExist4u(right))
        {
            throw new RightExistException("right already exist!");
        }

        try
        {
            Right entity = rightDAO.getRight(right.getId());

            // entity.setBox(right.getBox());
            // entity.setDesc(right.getDesc());
            // entity.setUrl(right.getUrl());
            MyBeanUtils.copyProperties(entity, right);
            rightDAO.updateRight(entity);
        } catch (DAOException e)
        {
            log.error("update right error: ", e);
            throw new BusinessException(e.getMessage());
        } catch (IllegalAccessException e)
        {
            log.error("update right error: ", e);
            throw new BusinessException(e.getMessage());
        } catch (InvocationTargetException e)
        {
            log.error("update right error: ", e);
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#updateRight(jaoso.framework.dto.RightDTO[])
     */
    public final void updateRight(final Right[] rights)
            throws BusinessException, RightExistException
    {
        if (MyUtils.isBlank(rights))
        {
            return;
        }

        for (int i = 0, n = rights.length; i < n; i++)
        {
            updateRight(rights[i]);
        }

        initSecurity();
    }

    /**
     * (non-Javadoc)
     * 
     * @see jaoso.framework.service.SecurityService#updateGroup(jaoso.framework.domain.Role,
     *      java.lang.String[], java.lang.String[])
     */
    public final void updateRole(final Role group, final String[] removeRight,
            final String[] addRight) throws BusinessException,
            GroupExistException
    {
        if ((group == null) || MyUtils.isBlank(group.getId()))
        {
            throw new BusinessException("group can not be null");
        }

        if (groupDAO.isExist(group.getDesc(), group.getId()))
        {
            throw new GroupExistException("group already exist!");
        }

        Role entity = findRoleById(group.getId());

        if (entity == null)
        {
            throw new BusinessException("group can not be null");
        }

        if (!MyUtils.isBlank(group.getDesc()))
        {
            entity.setDesc(group.getDesc());
        }

        Right right = null;

        //remove right
        if (!MyUtils.isBlank(removeRight))
        {
            for (int i = 0, n = removeRight.length; i < n; i++)
            {
                right = rightDAO.getRight(removeRight[i]);
                right.getGroups().remove(entity);
                entity.getRights().remove(right);
                rightDAO.updateRight(right);
            }
        }

        //add right
        if (!MyUtils.isBlank(addRight))
        {
            for (int i = 0, n = addRight.length; i < n; i++)
            {
                right = rightDAO.getRight(addRight[i]);
                right.getGroups().add(entity);
                entity.getRights().add(right);
                rightDAO.updateRight(right);
            }
        }

        groupDAO.updateGroup(entity);
        initSecurity();
    }

    /**
     * load account by id
     * 
     * @param id
     *            account id
     * 
     * @return account
     * 
     * @throws BusinessException
     *             any error
     */
    private Account getAccount(final Serializable id) throws BusinessException
    {
        Account entity = null;

        try
        {
            entity = (Account) getQueryManager().findByPK(new Account(), id);
        } catch (DAOException e)
        {
            log.error(e);
            throw new BusinessException("getAccount error: " + e.getMessage());
        }

        return entity;
    }

    /**
     * DOCUMENT ME!
     * 
     * @return DOCUMENT ME!
     */
    private Map loadRights()
    {
        Map rightMap = new HashMap();
        Right[] rights = null;

        try
        {
            rights = rightDAO.findAllRight();
        } catch (DAOException e)
        {
            log.error("loadRights error: " + e);
        }

        Right right;
        Set groups;
        Role group;
        Collection protectedResources = new ArrayList();

        for (int i = 0, n = rights.length; i < n; i++)
        {
            right = rights[i];
            groups = right.getGroups();

            Map groupMap = new HashMap();

            if (!MyUtils.isBlank(groups))
            {
                for (Iterator it = groups.iterator(); it.hasNext();)
                {
                    String groupId = ((Role) it.next()).getId().trim();
                    groupMap.put(groupId, groupId);
                }
            }

            protectedResources.add(new ProtectedResource(right.getBox(), right
                    .getDesc(), right.getUrl()));
            rightMap.put(right.getUrl(), groupMap);
        }

        rightMap.put("protectedResources", protectedResources);

        return rightMap;
    }
}